"""
混合对话服务 - 结合 MySQL 和向量数据库
MySQL: 存储对话元数据、消息元数据、feedback
向量数据库: 存储消息内容，用于检索和上下文分析
"""

from typing import List, Optional, Dict, Any
from sqlalchemy.orm import Session
from sqlalchemy import desc, func
import uuid
import time
import json
import logging
from datetime import datetime

from app.models import User, Conversation, Message
from app.core.vector_store import get_vector_store
from app.services.conversation_service import ConversationService
from app.services.chroma_cache_service import chroma_cache_service

logger = logging.getLogger(__name__)


class HybridConversationService(ConversationService):
    """混合对话服务 - 继承原有服务并扩展向量数据库功能"""
    
    def __init__(self, db: Session):
        super().__init__(db)
        self.vector_store = None
        self._init_vector_store()
    
    def _init_vector_store(self):
        """初始化向量存储"""
        try:
            self.vector_store = get_vector_store()
            logger.info("[HybridService] 向量存储初始化成功")
        except Exception as e:
            logger.warning(f"[HybridService] 向量存储初始化失败: {e}")

    def _safe_parse_metadata(self, metadata):
        """安全解析metadata"""
        if not metadata:
            return None

        try:
            # 检查是否是SQLAlchemy的MetaData对象或其他特殊对象
            if hasattr(metadata, '__class__') and 'MetaData' in str(type(metadata)):
                logger.debug(f"[HybridService] 跳过SQLAlchemy MetaData对象: {type(metadata)}")
                return None

            if isinstance(metadata, str):
                # 检查是否是空字符串或无效JSON
                if not metadata.strip():
                    return None
                return json.loads(metadata)
            elif isinstance(metadata, dict):
                return metadata
            elif metadata is None:
                return None
            else:
                # 对于其他类型，先检查是否可以安全转换
                metadata_str = str(metadata)
                if metadata_str in ['None', '', 'MetaData()'] or metadata_str.startswith('MetaData('):
                    logger.debug(f"[HybridService] 跳过无效metadata字符串: {metadata_str}")
                    return None
                # 尝试解析为JSON
                return json.loads(metadata_str)
        except (json.JSONDecodeError, TypeError, ValueError, AttributeError) as e:
            logger.warning(f"[HybridService] 解析metadata失败: {e}, metadata: {metadata}, type: {type(metadata)}")
            return None
    
    def add_message_hybrid(
        self, 
        conversation_id: str, 
        role: str, 
        content: str,
        model_name: Optional[str] = None,
        temperature: Optional[str] = None,
        metadata: Optional[Dict[str, Any]] = None
    ) -> Message:
        """
        混合添加消息：
        1. 在 MySQL 中存储消息元数据（不含 content 或 content 为空）
        2. 在向量数据库中存储完整消息内容
        """
        try:
            # 1. 在 MySQL 中创建消息记录（content 设为空或摘要）
            message_id = str(uuid.uuid4())
            content_summary = content[:100] + "..." if len(content) > 100 else content
            
            # 创建 MySQL 消息记录
            message = Message(
                message_id=message_id,
                conversation_id=conversation_id,
                role=role,
                content=content_summary,  # 只存储摘要
                model_name=model_name,
                temperature=temperature,
                metadata=json.dumps(metadata) if metadata else None,
                feedback=0  # 默认反馈
            )
            
            self.db.add(message)
            
            # 更新对话统计
            conversation = self.get_conversation(conversation_id)
            if conversation:
                current_count = conversation.message_count if conversation.message_count is not None else 0
                setattr(conversation, 'message_count', current_count + 1)
                setattr(conversation, 'last_message_at', datetime.now())
                
                # 更新对话标题
                if role == "user" and conversation.message_count == 1 and (not conversation.title or conversation.title == "新对话"):
                    setattr(conversation, 'title', content[:50] + "..." if len(content) > 50 else content)
            
            self.db.commit()
            self.db.refresh(message)
            
            # 2. 在向量数据库中存储完整消息内容
            if self.vector_store:
                try:
                    vector_metadata = {
                        "type": "message",
                        "message_id": message_id,
                        "conversation_id": conversation_id,
                        "role": role,
                        "timestamp": str(int(time.time())),
                        "model_name": model_name or "unknown",
                        "source": "chat_session"
                    }
                    
                    # 添加额外元数据
                    if metadata:
                        for key, value in metadata.items():
                            if isinstance(value, (str, int, float, bool)):
                                vector_metadata[f"meta_{key}"] = value
                    
                    # 存储到向量数据库
                    self.vector_store.add_texts(
                        texts=[content],
                        metadatas=[vector_metadata],
                        ids=[f"msg_{message_id}"]
                    )
                    
                    logger.info(f"[HybridService] 消息已存储到向量数据库: {message_id}")
                    
                except Exception as e:
                    logger.error(f"[HybridService] 向量数据库存储失败: {e}")
                    # 向量存储失败不影响主流程
            
            return message
            
        except Exception as e:
            self.db.rollback()
            logger.error(f"[HybridService] 混合添加消息失败: {e}")
            raise
    
    def get_conversation_messages_hybrid(
        self, 
        conversation_id: str, 
        limit: int = 50, 
        offset: int = 0,
        include_content: bool = True
    ) -> List[Dict[str, Any]]:
        """
        混合获取对话消息：
        1. 从 MySQL 获取消息元数据
        2. 从向量数据库获取消息内容（如果需要）
        """
        try:
            # 1. 从 MySQL 获取消息元数据
            mysql_messages = self.get_conversation_messages(conversation_id, limit, offset)
            logger.info(f"[HybridService] MySQL中找到 {len(mysql_messages)} 条消息记录")
            
            if not include_content:
                # 只返回元数据
                return [
                    {
                        "id": msg.id,
                        "message_id": msg.message_id,
                        "conversation_id": msg.conversation_id,
                        "role": msg.role,
                        "content": msg.content,  # 摘要
                        "model_name": msg.model_name,
                        "temperature": msg.temperature,
                        "feedback": msg.feedback,
                        "created_at": msg.created_at.isoformat() if msg.created_at else None,
                        "metadata": self._safe_parse_metadata(msg.metadata)
                    }
                    for msg in mysql_messages
                ]
            
            # 2. 从向量数据库获取完整内容
            result_messages = []
            
            for msg in mysql_messages:
                message_data = {
                    "id": msg.id,
                    "message_id": msg.message_id,
                    "conversation_id": msg.conversation_id,
                    "role": msg.role,
                    "content": msg.content,  # 默认使用摘要
                    "model_name": msg.model_name,
                    "temperature": msg.temperature,
                    "feedback": msg.feedback,
                    "created_at": msg.created_at.isoformat() if msg.created_at else None,
                    "metadata": self._safe_parse_metadata(msg.metadata)
                }
                
                # 尝试从向量数据库获取完整内容
                if self.vector_store:
                    try:
                        logger.info(f"[HybridService] 尝试从向量数据库检索消息: {msg.message_id}")

                        # 方法1：直接通过文档ID检索（更高效）
                        doc_id = f"msg_{msg.message_id}"
                        try:
                            # 获取ChromaDB客户端和集合
                            chroma_client = self.vector_store._client
                            collection_name = self.vector_store._collection.name
                            collection = chroma_client.get_collection(collection_name)

                            # 直接通过ID获取文档
                            results = collection.get(
                                ids=[doc_id],
                                include=["documents", "metadatas"]
                            )

                            if results and results.get('documents') and len(results['documents']) > 0:
                                original_length = len(message_data["content"])
                                new_content = results['documents'][0]
                                message_data["content"] = new_content
                                logger.info(f"[HybridService] 成功从向量数据库获取消息内容: {doc_id} (原始ID: {msg.message_id}), 长度: {original_length} -> {len(new_content)}")
                            # 删除了未找到消息ID的警告日志，因为功能正常不影响使用

                        except Exception as direct_e:
                            logger.warning(f"[HybridService] 直接ID查询失败，尝试metadata过滤: {direct_e}")

                            # 方法2：备用方案 - 使用metadata过滤查询
                            docs = self.vector_store.similarity_search(
                                query="",  # 空查询
                                k=1,
                                filter={"message_id": {"$eq": msg.message_id}}
                            )

                            if docs:
                                original_length = len(message_data["content"])
                                new_content = docs[0].page_content
                                message_data["content"] = new_content
                                logger.info(f"[HybridService] 通过metadata过滤成功获取消息内容: {msg.message_id}, 长度: {original_length} -> {len(new_content)}")
                            else:
                                logger.warning(f"[HybridService] 向量数据库中未找到消息: {msg.message_id}")

                    except Exception as e:
                        logger.error(f"[HybridService] 向量数据库检索失败: {e}")
                        # 使用 MySQL 中的摘要内容
                
                result_messages.append(message_data)
            
            return result_messages
            
        except Exception as e:
            logger.error(f"[HybridService] 混合获取消息失败: {e}")
            return []
    
    def update_message_feedback(self, message_id: str, feedback: int) -> bool:
        """
        更新消息反馈（只在 MySQL 中更新）
        """
        try:
            message = self.db.query(Message).filter(Message.message_id == message_id).first()
            if not message:
                logger.warning(f"[HybridService] 消息不存在: {message_id}")
                return False
            
            message.feedback = feedback
            self.db.commit()
            
            logger.info(f"[HybridService] 消息反馈已更新: {message_id} -> {feedback}")
            return True
            
        except Exception as e:
            self.db.rollback()
            logger.error(f"[HybridService] 更新消息反馈失败: {e}")
            return False
    
    def search_messages_by_content(
        self, 
        query: str, 
        conversation_id: Optional[str] = None,
        user_id: Optional[str] = None,
        limit: int = 10
    ) -> List[Dict[str, Any]]:
        """
        基于内容搜索消息（使用向量数据库）
        """
        try:
            if not self.vector_store:
                logger.warning("[HybridService] 向量存储不可用")
                return []
            
            # 构建过滤条件（ChromaDB 格式）
            if conversation_id:
                filter_conditions = {
                    "$and": [
                        {"type": {"$eq": "message"}},
                        {"conversation_id": {"$eq": conversation_id}}
                    ]
                }
            else:
                filter_conditions = {"type": {"$eq": "message"}}

            # 执行向量搜索
            docs = self.vector_store.similarity_search_with_score(
                query=query,
                k=limit,
                filter=filter_conditions
            )
            
            results = []
            for doc, score in docs:
                metadata = doc.metadata
                results.append({
                    "message_id": metadata.get("message_id"),
                    "conversation_id": metadata.get("conversation_id"),
                    "role": metadata.get("role"),
                    "content": doc.page_content,
                    "similarity_score": float(score),
                    "timestamp": metadata.get("timestamp"),
                    "model_name": metadata.get("model_name")
                })
            
            logger.info(f"[HybridService] 内容搜索完成: {len(results)} 个结果")
            return results
            
        except Exception as e:
            logger.error(f"[HybridService] 内容搜索失败: {e}")
            return []
    
    def get_conversation_history(
        self,
        conversation_id: str,
        limit: int = 50
    ) -> List[Message]:
        """
        获取对话历史（兼容方法）
        返回 Message 对象列表，用于与现有代码兼容
        """
        try:
            logger.info(f"[HybridService] 获取对话历史: conversation_id={conversation_id}, limit={limit}")

            # 使用父类的方法获取消息
            messages = self.get_conversation_messages(conversation_id, limit)

            logger.info(f"[HybridService] 从MySQL获取到 {len(messages)} 条历史消息")
            return messages

        except Exception as e:
            logger.error(f"[HybridService] 获取对话历史失败: {e}")
            return []

    def get_user_conversation_history_from_chroma(
        self,
        user_id: str,
        limit: int = 50,
        exclude_conversation_id: str = None
    ) -> List[Dict[str, Any]]:
        """
        从ChromaDB获取用户的对话历史
        """
        try:
            logger.info(f"[HybridService] 从ChromaDB获取用户历史: user_id={user_id}, limit={limit}")

            if not self.vector_store:
                logger.warning("[HybridService] 向量存储未初始化")
                return []

            # 构建过滤条件
            filter_conditions = [
                {"user_id": {"$eq": user_id}},
                {"type": {"$eq": "message"}}
            ]

            # 排除当前对话
            if exclude_conversation_id:
                filter_conditions.append(
                    {"conversation_id": {"$ne": exclude_conversation_id}}
                )

            # 查询用户的历史消息
            docs = self.vector_store.similarity_search(
                query="历史对话",  # 使用通用查询
                k=limit,
                filter={"$and": filter_conditions}
            )

            logger.info(f"[HybridService] 从ChromaDB找到 {len(docs)} 条用户历史消息")

            # 转换为消息格式
            history_messages = []
            for doc in docs:
                metadata = doc.metadata
                history_messages.append({
                    "content": doc.page_content,
                    "role": metadata.get("role", "unknown"),
                    "conversation_id": metadata.get("conversation_id"),
                    "message_id": metadata.get("message_id"),
                    "timestamp": metadata.get("timestamp"),
                    "created_at": metadata.get("created_at")
                })

            # 按时间排序（最新的在前）
            history_messages.sort(
                key=lambda x: x.get("timestamp", 0) or x.get("created_at", ""),
                reverse=True
            )

            return history_messages

        except Exception as e:
            logger.error(f"[HybridService] 从ChromaDB获取用户历史失败: {e}")
            return []

    def get_conversation_context(
        self,
        conversation_id: str,
        query: str,
        limit: int = 5
    ) -> List[Dict[str, Any]]:
        """
        获取对话相关上下文（基于向量检索）
        """
        try:
            if not self.vector_store:
                return []

            # 检索相关的历史消息（使用正确的 ChromaDB 过滤格式）
            docs = self.vector_store.similarity_search_with_score(
                query=query,
                k=limit,
                filter={
                    "$and": [
                        {"conversation_id": {"$eq": conversation_id}},
                        {"type": {"$eq": "message"}}
                    ]
                }
            )

            context = []
            for doc, score in docs:
                metadata = doc.metadata
                context.append({
                    "content": doc.page_content,
                    "role": metadata.get("role"),
                    "similarity_score": float(score),
                    "timestamp": metadata.get("timestamp")
                })

            return context

        except Exception as e:
            logger.error(f"[HybridService] 获取对话上下文失败: {e}")
            return []

    def delete_conversation_hybrid(self, conversation_id: str) -> bool:
        """
        混合删除对话：
        1. 从向量数据库删除所有相关消息（如果可能）
        2. 从 MySQL 删除对话和消息记录
        """
        try:
            logger.info(f"[HybridService] 开始删除对话: {conversation_id}")

            # 1. 尝试从向量数据库删除相关消息
            vector_delete_success = self._delete_from_vector_store(conversation_id)

            # 2. 从 MySQL 删除消息和对话（这是主要的删除操作）
            # 先删除消息
            deleted_messages = self.db.query(Message).filter(
                Message.conversation_id == conversation_id
            ).delete()

            # 再删除对话
            deleted_conversations = self.db.query(Conversation).filter(
                Conversation.conversation_id == conversation_id
            ).delete()

            self.db.commit()

            logger.info(f"[HybridService] MySQL删除完成: {deleted_messages} 条消息, {deleted_conversations} 个对话")

            if not vector_delete_success:
                logger.warning(f"[HybridService] 向量数据库删除失败，但MySQL删除成功")

            return deleted_conversations > 0

        except Exception as e:
            self.db.rollback()
            logger.error(f"[HybridService] 删除对话失败: {e}")
            return False

    def _delete_from_vector_store(self, conversation_id: str) -> bool:
        """从向量数据库删除对话相关的所有消息"""
        if not self.vector_store:
            logger.warning("[HybridService] 向量存储不可用，跳过向量数据库删除")
            return False

        try:
            # 获取ChromaDB客户端和集合
            chroma_client = self.vector_store._client
            collection_name = self.vector_store._collection.name
            collection = chroma_client.get_collection(collection_name)

            # 查询所有属于该对话的文档ID
            try:
                # 使用where条件查询
                results = collection.get(
                    where={"conversation_id": conversation_id},
                    include=["metadatas"]
                )

                if results and results.get('ids'):
                    doc_ids = results['ids']
                    logger.info(f"[HybridService] 找到 {len(doc_ids)} 个向量文档需要删除")

                    # 批量删除文档
                    collection.delete(ids=doc_ids)
                    logger.info(f"[HybridService] 成功从向量数据库删除 {len(doc_ids)} 个文档")
                    return True
                else:
                    logger.info(f"[HybridService] 向量数据库中未找到对话 {conversation_id} 的相关文档")
                    return True  # 没有文档需要删除也算成功

            except Exception as query_e:
                logger.warning(f"[HybridService] 向量数据库查询失败，尝试备用删除方法: {query_e}")
                # 备用方法：尝试直接删除（可能会失败，但不影响主流程）
                return False

        except Exception as e:
            logger.error(f"[HybridService] 向量数据库删除操作失败: {e}")
            return False

    def update_conversation_title_hybrid(self, conversation_id: str, new_title: str) -> bool:
        """
        更新对话标题（只在 MySQL 中更新，向量数据库不需要更新标题）
        """
        try:
            logger.info(f"[HybridService] 更新对话标题: {conversation_id} -> {new_title}")

            conversation = self.db.query(Conversation).filter(
                Conversation.conversation_id == conversation_id
            ).first()

            if not conversation:
                logger.warning(f"[HybridService] 对话不存在: {conversation_id}")
                return False

            conversation.title = new_title
            self.db.commit()

            logger.info(f"[HybridService] 对话标题更新成功")
            return True

        except Exception as e:
            self.db.rollback()
            logger.error(f"[HybridService] 更新对话标题失败: {e}")
            return False
